package com.chenju.javastatic;

import com.chenju.javastatic.component.config.TargetProjectConfig;
import com.chenju.javastatic.domain.pojo.DiffPoJo;
import com.chenju.javastatic.service.EasyTestService;
import com.chenju.javastatic.service.JavaParserService;
import com.chenju.javastatic.service.Neo4JService;
import com.chenju.javastatic.utils.EasyDiffUtils;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.*;
import org.springframework.asm.Opcodes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.*;
import java.util.List;
import java.util.jar.JarInputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@SpringBootTest
class JavaStaticApplicationTests {

    @Test
    void contextLoads() {
    }

    @Test
    void testConfig() {
        System.out.println(TargetProjectConfig.getPackagesStringArray());
    }
    // 读取类字节码
    private static byte[] readClassBytes(JarInputStream jarInputStream) throws IOException {
        byte[] buffer = new byte[8192];
        int bytesRead;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        while ((bytesRead = jarInputStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }
        return byteArrayOutputStream.toByteArray();
    }

    @Test
    void testVisit(){
        String input = "M:com/chenju/invokechainservice/component/BuildComponent:<Ljava/lang/String;>getBuildFileName([]) (INVOKESTATIC)com/chenju/invokechainservice/component/BuildComponent:<Ljava/lang/String;>getBuildTool([])";

        // 定义正则表达式
        String regex = "M:(.*?):<(.+?)>(.*?)\\((.*?)\\) \\((.*?)\\)(.*?):<(.+?)>(.*?)\\((.*?)\\)";

        // 编译正则表达式
        Pattern pattern = Pattern.compile(regex);

        // 匹配输入字符串
        Matcher matcher = pattern.matcher(input);

        // 提取匹配到的信息
        if (matcher.find()) {
            String component1 = matcher.group(1);
            String returnType1 = matcher.group(2);
            String methodName1 = matcher.group(3);
            String params1 = matcher.group(4);
            String invokeType = matcher.group(5);
            String component2 = matcher.group(6);
            String returnType2 = matcher.group(7);
            String methodName2 = matcher.group(8);
            String params2 = matcher.group(9);

            // 输出结果
            System.out.println("Component 1: " + component1);
            System.out.println("Return Type 1: " + returnType1);
            System.out.println("Method Name 1: " + methodName1);
            System.out.println("Params 1: " + params1);
            System.out.println("Invoke Type: " + invokeType);
            System.out.println("Component 2: " + component2);
            System.out.println("Return Type 2: " + returnType2);
            System.out.println("Method Name 2: " + methodName2);
            System.out.println("Params 2: " + params2);
        } else {
            System.out.println("No match found.");
        }
    }

    @Test
    void testMain() throws IOException {
        // 读取类字节码
        // 创建 ClassReader
        ClassReader classReader = new ClassReader(new FileInputStream(new File("D:\\Project\\springboot-easytest\\invokechain-service\\target\\classes\\com\\chenju\\invokechainservice\\service\\impl\\FunnyTestServiceImplement.class")));

        // 创建 ClassVisitor
        classReader.accept(new ClassVisitor(Opcodes.ASM9) {
            @Override
            public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
                System.out.printf("class name : %s\n", name);
                super.visit(version, access, name, signature, superName, interfaces);
            }

            @Override
            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                System.out.printf("method name : %s%s\n", name, descriptor);
                // 返回一个新的 MethodVisitor
                return new MethodVisitor(Opcodes.ASM9) {
                    @Override
                    public void visitLineNumber(int line, Label start) {
                        // 访问行号信息
//                        System.out.println("Line Number: " + line);
                    }

                    @Override
                    public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
                        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
                    }

                    @Override
                    public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
                        System.out.printf("MethodHandle: %s:%s\n", bootstrapMethodHandle.getOwner(), bootstrapMethodHandle.getName());
                        for (Object obj : bootstrapMethodArguments) {
                            if (obj instanceof Handle) {
                                System.out.printf("INVOKE %S.%s%s", ((Handle) obj).getOwner(), ((Handle) obj).getName(), ((Handle) obj).getDesc());
                            }
                        }
                        super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
                    }

                    // 其他方法的实现...
                };
            }
        }, 0);
    }

    @Autowired
    private EasyTestService easyTestService;
    @Test
    void testEasyTest() {
        String jarPath = "D:\\Project\\springboot-easytest-simple\\java-static\\target\\java-static-0.0.1-SNAPSHOT.jar";
//        String jarPath = "D:\\Project\\springboot-easytest\\invokechain-service\\target\\invokechain-service-0.0.1-SNAPSHOT.jar";
        easyTestService.parse(jarPath, "java-static");
    }

    @Test
    void testParseProject() {
        easyTestService.parseProject();
    }

    @Test
    void testImplements() throws IOException {
        ClassReader classReader = new ClassReader(new FileInputStream("D:\\Project\\javacall\\springboot-easytest-simple\\java-static\\target\\test-classes\\com\\chenju\\javastatic\\JavaStaticApplicationTests.class")); // 替换为实现了接口的类名
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        classReader.accept(new ClassVisitor(Opcodes.ASM9, classWriter) {
            @Override
            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
                return new MethodVisitor(Opcodes.ASM9, mv) {
                    @Override
                    public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
                        if (isInterface && owner.equals("com.chenju.javastatic.service.EasyTestService")) { // 替换为接口的全限定名
                            System.out.println("方法名: " + name + ", 描述符: " + descriptor);
                        }
                        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
                    }
                };
            }
        }, 0);
    }

    @Autowired
    Neo4JService neo4JService;
    @Test
    void testNeo4J() {
        neo4JService.batchInsert();
    }

    @Autowired
    JavaParserService javaParserService;
    @Test
    void testJavaParserBranch() {
        File repoDir = new File("D:\\Project\\springboot-easytest");
        String oldBranchName = "master";
        String newBranchName = "release_20240425";
        List<DiffPoJo> diffPoJos = javaParserService.parseBranchDiff("", repoDir, oldBranchName, newBranchName);

        diffPoJos.forEach(diffPoJo -> System.out.println(diffPoJo.toString()));
    }

    @Test
    void testJavaParserCommit() {
        File repoDir = new File("D:\\Project\\springboot-easytest-simple");
        String oldCommitName = "ee3bf2b";
        String newCommitName = "528f416";
        List<DiffPoJo> diffPoJos = javaParserService.parseCommitDiff("", repoDir, oldCommitName, newCommitName);

//        diffPoJos.forEach(diffPoJo -> System.out.println(diffPoJo.toString()));
        diffPoJos.forEach(diffPoJo -> EasyDiffUtils.diff(diffPoJo.getOldContent(), diffPoJo.getNewContent()));
    }

    @Test
    void testNeoSelect() {
        String sql = "Match p=(m:MethodNode)-[r]->(n) RETURN m,p,n";
        neo4JService.excute(sql);
        // InternalNode
        // InternalPath
        //
    }
}
